home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / pyshared / computerjanitor / plugin.py < prev   
Encoding:
Python Source  |  2009-04-27  |  6.1 KB  |  183 lines

  1. # plugin.py - plugin base class for computerjanitor
  2. # Copyright (C) 2008  Canonical, Ltd.
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, version 3 of the License.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  15.  
  16.  
  17. import imp
  18. import inspect
  19. import logging
  20. import os
  21.  
  22. import computerjanitor
  23. _ = computerjanitor.setup_gettext()
  24. import logging
  25.  
  26. class Plugin(object):
  27.  
  28.     """Base class for plugins.
  29.     
  30.     These plugins only do one thing: identify cruft. See the 'get_cruft'
  31.     method for details.
  32.     
  33.     """
  34.  
  35.     def get_condition(self):
  36.         if hasattr(self, "_condition"):
  37.             return self._condition
  38.         else:
  39.             return []
  40.             
  41.     def set_condition(self, condition):
  42.         self._condition = condition
  43.  
  44.     condition = property(get_condition, set_condition)
  45.     
  46.     def set_application(self, app):
  47.         """Set the Application instance this plugin belongs to.
  48.         
  49.         This is used by the plugin manager when creating the plugin
  50.         instance. In a perfect world, this would be done via the
  51.         __init__ method, but since I took a wrong left turn, I ended
  52.         up in an imperfect world, and therefore giving the Application
  53.         instance to __init__ would mandate that all sub-classes would
  54.         have to deal with that explicitly. That is a lot of unnecessary
  55.         make-work, which we should avoid. Therefore, we do it via this
  56.         method.
  57.         
  58.         The class may access the Application instance via the
  59.         'app' attribute.
  60.         
  61.         """
  62.         
  63.         self.app = app
  64.  
  65.     def do_cleanup_cruft(self): # pragma: no cover
  66.         """Find cruft and clean it up.
  67.  
  68.         This is a helper method.
  69.         """
  70.  
  71.         for cruft in self.get_cruft():
  72.             cruft.cleanup()
  73.         self.post_cleanup()
  74.  
  75.     def get_cruft(self):
  76.         """Find some cruft in the system.
  77.         
  78.         This method MUST return an iterator (see 'yield' statement).
  79.         This interface design allows cruft to be collected piecemeal,
  80.         which makes it easier to show progress in the user interface.
  81.         
  82.         The base class default implementation of this raises an
  83.         exception. Subclasses MUST override this method.
  84.  
  85.         """
  86.  
  87.         raise computerjanitor.UnimplementedMethod(self.get_cruft)
  88.  
  89.     def post_cleanup(self):
  90.         """Does plugin wide cleanup after the individual cleanup
  91.            was performed.
  92.            
  93.            This is useful for stuff that needs to be proccessed
  94.            in batches (e.g. for performance reasons) like package
  95.            removal.
  96.         """
  97.         pass
  98.  
  99.  
  100. class PluginManager(object):
  101.  
  102.     """Class to find and load plugins.
  103.     
  104.     Plugins are stored in files named '*_plugin.py' in the list of
  105.     directories given to the initializer.
  106.     
  107.     """
  108.     
  109.     def __init__(self, app, plugin_dirs):
  110.         self._app = app
  111.         self._plugin_dirs = plugin_dirs
  112.         self._plugins = None
  113.  
  114.     def get_plugin_files(self):
  115.         """Return all filenames in which plugins may be stored."""
  116.         
  117.         names = []
  118.         
  119.         for dirname in self._plugin_dirs:
  120.             basenames = [x for x in os.listdir(dirname) 
  121.                             if x.endswith("_plugin.py")]
  122.             logging.debug("Plugin modules in %s: %s" % 
  123.                             (dirname, " ".join(basenames)))
  124.             names += [os.path.join(dirname, x) for x in basenames]
  125.         
  126.         return names
  127.  
  128.     def _find_plugins(self, module):
  129.         """Find and instantiate all plugins in a module."""
  130.         plugins = []
  131.         for dummy, member in inspect.getmembers(module):
  132.             if inspect.isclass(member) and issubclass(member, Plugin):
  133.                 plugins.append(member)
  134.         logging.debug("Plugins in %s: %s" %
  135.                       (module, " ".join(str(x) for x in plugins)))
  136.         return [plugin() for plugin in plugins]
  137.  
  138.     def _load_module(self, filename):
  139.         """Load a module from a filename."""
  140.         logging.debug("Loading module %s" % filename)
  141.         module_name, dummy = os.path.splitext(os.path.basename(filename))
  142.         f = file(filename, "r")
  143.         try:
  144.             module = imp.load_module(module_name, f, filename,
  145.                                      (".py", "r", imp.PY_SOURCE))
  146.         except Exception, e: # pragma: no cover
  147.             logging.warning("Failed to load plugin '%s' (%s)" % 
  148.                             (module_name, e))
  149.             return None
  150.         f.close()
  151.         return module
  152.  
  153.     def get_plugins(self, condition=[], callback=None):
  154.         """Return all plugins that have been found.
  155.         
  156.         If callback is specified, it is called after each plugin has
  157.         been found, with the following arguments: filename, index of
  158.         filename in list of files to be examined (starting with 0), and
  159.         total number of files to be examined. The purpose of this is to
  160.         allow the callback to inform the user in case things take a long
  161.         time.
  162.         
  163.         """
  164.  
  165.         if self._plugins is None:
  166.             self._plugins = []
  167.             filenames = self.get_plugin_files()
  168.             for i in range(len(filenames)):
  169.                 if callback:
  170.                     callback(filenames[i], i, len(filenames))
  171.                 module = self._load_module(filenames[i])
  172.                 for plugin in self._find_plugins(module):
  173.                     plugin.set_application(self._app)
  174.                     self._plugins.append(plugin)
  175.         # get the matching plugins
  176.         plugins = [p for p in self._plugins 
  177.                    if (p.condition == condition) or
  178.                    (condition in p.condition) or
  179.                    (condition == "*") ]
  180.         logging.debug("plugins for condition '%s' are '%s'" %
  181.                       (condition, plugins))
  182.         return plugins
  183.